﻿#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <vector>
#include <queue>
#include <memory>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <unordered_map>

class Semaphore
{
public:
	Semaphore(int limit = 0) : resLimit_(limit) {}
	~Semaphore() = default;

	// 获得一个信号量资源
	void wait()
	{
		std::unique_lock<std::mutex> lock(mutex_);
		// 等待信号量有资源，没有资源阻塞
		cond_.wait(lock, [&]()->bool { return resLimit_ > 0; });
		resLimit_--;
	}
	// 释放一个信号量资源
	void post()
	{
		std::unique_lock<std::mutex> lock(mutex_);
		resLimit_++;
		cond_.notify_all();
	}

private: 
	int resLimit_;
	std::mutex mutex_;
	std::condition_variable cond_;
};

class Task;

class Any
{
public:
	Any() = default;
	~Any() = default;
	Any(const Any&) = delete;
	Any& operator=(const Any&) = delete;
	Any(Any&&) = default;
	Any& operator=(Any&&) = default;

	// 这个构造方法，可以使用任意类型来构造Any类
	template<typename T>
	Any(T data)
		// : base_(new Derive<T>(data))
		: base_(std::make_unique<Derive<T>>(data))
	{
	}

	// 这个方法，能够让Any对象里面存储的data数据提取出来
	template <typename T>
	T cast_()
	{
		// 从base_指向的Derive派生类对象中提取出data成员变量
		Derive<T>* pd = dynamic_cast<Derive<T>*>(base_.get());
		if (pd == nullptr)
		{
			throw "type is unmatch";
		}
		return pd->data_;
	}
private:
	// 基类类型
	class Base
	{
	public:
		virtual ~Base() = default;
	};

	// 派生类类型
	template<typename T>
	class Derive : public Base
	{
	public:
		Derive(T data) : data_(data)
		{
		}
		T data_; // 存储值的地方
	};
private:
	std::unique_ptr<Base> base_; // 指向一个继承自这个基类的子类对象
};

// 线程执行完任务返回结果的类型（不知道用户需要任务返回什么类型，要一个能接收所有类型的类型）
// 实现提交到线程池的task任务执行完后的返回值类型Reuslt
class Result
{
public:
	Result(std::shared_ptr<Task> task, bool isVaild = true);
	~Result() = default;

	// setVal 获得任务执行完的返回值
	void setVal(Any any);
	// get    用户调用这个方法获得task的返回值
	Any get();

private:
	Any any_; // 存储任务的返回值
	// 因为如果工作线程没有执行完任务，用户线程在调用get()的时候要把用户线程阻塞住，用一个信号量
	Semaphore sem_; // 线程通信信号量

	std::shared_ptr<Task> task_; // 指向对应将来获取返回值的任务对象
	std::atomic_bool isVaild_; // 返回值是否有效
};



// 任务抽象基类 - 用户传入的任务的类型（不知道用户会传入什么类型的任务）
class Task
{
public:
	Task();
	~Task() = default;

	void exec();
	void setReuslt(Result* result);

	// 用户可以定义任意任务类型，从Task继承而来，重写run方法，实现自定义任务处理
	virtual Any run() = 0;
private:
	Result* result_;
};

// 线程池的工作模式
enum class PoolMode
{
	MODE_FIXED,  // 固定数量的线程池
	MODE_CACHED, // 线程数量可动态变化的线程池
};

// 线程类型
class Thread
{
public:
	// 线程函数对象类型
	using ThreadFunc = std::function<void(int)>;

	// 线程构造
	Thread(ThreadFunc func);
	// 线程析构
	~Thread();
	// 启动线程
	void start();
	// 获得线程ID
	int getId() const;

private:
	ThreadFunc func_;
	static int generateId_;
	int threadId_;
};

// 线程池类型
class ThreadPool
{
public:
	// 线程池构造
	ThreadPool();

	// 线程池析构
	~ThreadPool();

	// 开启线程池
	void start(int initThreadSize = std::thread::hardware_concurrency());

	// 设置线程池模式
	void setMode(PoolMode mode);

	// 设置线程池任务队列最大数量
	void setTaskQueMaxThreshHold(int threshhold);

	// 给线程池提交任务
	Result submitTask(std::shared_ptr<Task> sp);

	// 线程函数
	void threadFunc(int threadId);

	// 设置线程数量的上限
	void setThreadMaxThreshHold(int threshhold);

	ThreadPool(const ThreadPool&) = delete;
	ThreadPool& operator=(const ThreadPool&) = delete;

public:
	// 检查线程池的运行状态
	bool checkRunningState() const;

private:

	// std::vector<std::unique_ptr<Thread>> threads_; // 线程列表
	std::unordered_map<int, std::unique_ptr<Thread>> threads_;
	int initThreadSize_;                           // 初始的线程数量
	int threadSizeThreshHold_;                     // 线程数量的上限阈值
	std::atomic_int curThreadSize_;            // 记录当前线程池中的线程个数
	std::atomic_int idleThreadSize_;               // 记录空闲线程的数据量

	std::queue<std::shared_ptr<Task>> taskQue_; // 任务队列
	std::atomic_int taskSize_;                  // 任务数量
	int	taskQueMaxThreshHold_;                  // 任务队列上限阈值

	std::mutex taskQueMtx_;                     // 保证任务队列的线程安全
	std::condition_variable notFull_;           // 任务队列不满
	std::condition_variable notEmpty_;          // 任务队列不空
	std::condition_variable exitCond_;

	PoolMode poolMode_;              // 线程池的工作模式
	std::atomic_bool isPoolRunning_; // 表示线程池的启动状态
};

#endif